const path=require("path");
const Koa=require("koa");
const logger=require("koa-logger");//产生日志记录
const onerror=require("koa-onerror");//错误链接和转换显示功能
const serve=require("koa-static");
// koa-body 自动完成请求报文解析操作的 = 支持所有的请求报文体的参数类型，并会自动识别
//          并将解析后的报文体参数 定义于 ctx.request.body 中
//          并将解析后的报文体文件数据 定义于 ctx.request.files 中
const koaBody=require("koa-body");
const router=require("./router");

const app=new Koa();
app.use(logger());//日志：记录开发中所有的操作流程，当开发出现错误时候，可以快速完成错误定位以及触发错误的源头和执行过程
onerror(app);  // 将控制台错误 映射到 浏览器页面中

app.use(koaBody({
    multipart:true,//支持文件上传
    formidable:{
        uploadDir:path.join(__dirname,'./public/upload'),//设置上传文件由二进制数据转上传到服务器的存放目录，文件存储时会完成重新命名操作
        keepExtensions:true//设置是否保留上传文件的后缀名(默认是false)
    }
}));

/* 
静态资源处理中间件(图片，视频，css，js...),不需要服务器进行处理可以直接进行访问的资源
    koa-static中间件可以在koa请求处理时候，判断浏览器访问的相关资源在对应的静态资源目录中是否存在
    如果存在则直接返回该静态资源的相关数据，且中间件不再调用next函数
    如果不存在则直接调用next函数函数访问下一个中间件
koa-static中间件一般被定义在koa请求响应处理中间件的第一行
koa-static中间件在定义时,需要指定一个项目目录作为静态资源的存放目录
koa-static指定的静态资源存放目录，从项目结构上来说，可以认为是服务器的根目录
 */
// app.use(serve("./public"));
let staticPath=path.join(__dirname,'./public');
app.use(serve(staticPath));

app.use(async function(ctx,next){
    ctx.set("Access-Control-Allow-Origin","*");//允许指定域名的跨源请求
    // HTTP 复杂请求
    // 允许的跨域请求方法的类型
    ctx.set("Access-Control-Allow-Methods","GET,POST,OPTIONS,PUT,DELETE,PATCH");
    ctx.set("Access-Control-Allow-Headers","Content-Type,test,Authorization");
    // 统一的测试请求结果处理
    if(ctx.method=="OPTIONS"){
        ctx.body = "";
    }else{
        await next();
    }
})

const token = require("jsonwebtoken");
let tokenConfig = { 
    sign:token.sign,
    secret:"itant secret" 
}

app.use( async function(ctx,next){
    try {
        ctx.token = tokenConfig;
        await next();
    } catch (error) {
        // console.log("===>",error)
        // console.log("===>",error.status)
        if(error.status==401){
            ctx.status = 401;
            ctx.body = {
                state:false,
                msg:"未授权"
            }
        }else{
            // throw 不对错误进行任何处理，直接进行返回
            throw error;
        }
    }
} )

const jwt = require("koa-jwt");
//  jwt({ sign:加密方法,secret:加密秘钥 })  // 解码+判断授权
//      .unless({ path:正则 }) // 定义不需要判断的路由地址
// app.use( jwt({ sign:加密方法,secret:加密秘钥 }).unless({ path:正则 }) )
app.use( jwt(tokenConfig).unless( { path:[/^\/api\//] } ) )

//router是路由定义对象，用于提供定义时地址和回调函数之间的对应关系
// router完成关系定义后，由router.routes()方法执行完成路由表的生成
// 路由表->一段js的路由和方法对应的判断逻辑
app.use(router.api.routes());
app.use(router.user.routes());


app.listen(3000);